/**************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 mian.c
作者	   : 左忠凯
版本	   : V1.0
描述	   : I.MX6U开发板裸机实验21 背光PWM实验
其他	   : 我们使用手机的时候背光都是可以调节的，同样的ZERO-I.MX6U
		 开发板的LCD背光也是可以调节，LCD背光就相当于一个LED灯。
		 LED灯的亮灭可以通过PWM来控制，本实验我们就来学习一下如何
		 通过PWM来控制LCD的背光。
论坛 	   : www.openedv.com
在线教育	: www.yuanzige.com
日志	   : 初版V1.0 2019/1/21 左忠凯创建
**************************************************************/
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"
#include "bsp_int.h"
#include "bsp_uart.h"
#include "bsp_lcd.h"
#include "bsp_lcdapi.h"
#include "bsp_rtc.h"
#include "bsp_backlight.h"
#include "stdio.h"
#include "bsp_ft5xx6.h"
#include "bsp_gt9147.h"
/* Kernel includes. */
#include "FreeRTOS.h" /* Must come first. */
#include "queue.h"		/* RTOS queue related API prototypes. */
#include "semphr.h"		/* Semaphore related API prototypes. */
#include "task.h"			/* RTOS task related API prototypes. */
#include "timers.h"		/* Software timer related API prototypes. */
// littleVGL
#ifdef LITTLE_VGL_ENABLE
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "lv_conf.h"
#include "lv_ex_conf.h"
#endif
/*
 * @description	: 使能I.MX6U的硬件NEON和FPU
 * @param 		: 无
 * @return 		: 无
 */
void imx6ul_hardfpu_enable(void)
{
	uint32_t cpacr;
	uint32_t fpexc;

	/* 使能NEON和FPU */
	cpacr = __get_CPACR();
	cpacr = (cpacr & ~(CPACR_ASEDIS_Msk | CPACR_D32DIS_Msk)) | (3UL << CPACR_cp10_Pos) | (3UL << CPACR_cp11_Pos);
	__set_CPACR(cpacr);
	fpexc = __get_FPEXC();
	fpexc |= 0x40000000UL;
	__set_FPEXC(fpexc);
}

#define vglSOFTWARE_TIMER_PERIOD_MS pdMS_TO_TICKS(5)
// 句柄
TimerHandle_t VGLSoftwareTimer = NULL;
static TaskHandle_t StartTask1_Handler;
static TaskHandle_t StartTask2_Handler;
// 任务函数
void start_task1(void *pvParameters);
void start_task2(void *pvParameters);

static void VGLTimerCallback(TimerHandle_t xTimer);

#ifdef CAT_SYSTEM_STATUS
static TaskHandle_t cputask_Handler;
void cpu_task(void *pvParameters);
#endif

void prvSetupHardware(void)
{
	imx6ul_hardfpu_enable(); /* 使能I.MX6U的硬件浮点 			*/
	int_init();							 /* 初始化中断(一定要最先调用！) */
	imx6u_clkinit();				 /* 初始化系统时钟 					*/
	/* 初始化延时 但初始化外设完成后重新初始化gpt1作为freertos系统时钟 */
	delay_init();
	clk_enable();			/* 使能所有的时钟 					*/
	led_init();				/* 初始化led 					*/
	beep_init();			/* 初始化beep	 				*/
	uart_init();			/* 初始化串口，波特率115200 */
	lcd_init();				/* 初始化LCD 					*/
	backlight_init(); /* 初始化背光PWM			 		*/
	/* 初始化触摸屏					*/
	if (tftlcd_dev.id == ATK7016 || tftlcd_dev.id == ATK7084)
	{
		ft5426_init();
	}
	else if (tftlcd_dev.id == ATK4384 || tftlcd_dev.id == ATK4342)
	{
		gt9147_init();
	}
#ifdef LITTLE_VGL_ENABLE
	lv_init();
	lv_port_disp_init();
	lv_port_indev_init();
#if LV_USE_DEMO_WIDGETS
	lv_demo_widgets();
#endif
#if LV_USE_DEMO_BENCHMARK
	lv_demo_benchmark();
#endif
#else
	tftlcd_dev.forecolor = LCD_RED;
	lcd_show_string(50, 10, 400, 24, 24, (char *)"ZERO-IMX6U BACKLIGHT PWM TEST");
	lcd_show_string(50, 40, 200, 16, 16, (char *)"ATOM@ALIENTEK");
	lcd_show_string(50, 60, 200, 16, 16, (char *)"2019/3/27");
	lcd_show_string(50, 90, 400, 16, 16, (char *)"PWM Duty:   %");

	lcd_show_string(300, 110, 400, 16, 16, (char *)"TP Num	:");
	lcd_show_string(300, 130, 200, 16, 16, (char *)"Point0 X:");
	lcd_show_string(300, 150, 200, 16, 16, (char *)"Point0 Y:");
	lcd_show_string(300, 170, 200, 16, 16, (char *)"Point1 X:");
	lcd_show_string(300, 190, 200, 16, 16, (char *)"Point1 Y:");
	lcd_show_string(300, 210, 200, 16, 16, (char *)"Point2 X:");
	lcd_show_string(300, 230, 200, 16, 16, (char *)"Point2 Y:");
	lcd_show_string(300, 250, 200, 16, 16, (char *)"Point3 X:");
	lcd_show_string(300, 270, 200, 16, 16, (char *)"Point3 Y:");
	lcd_show_string(300, 290, 200, 16, 16, (char *)"Point4 X:");
	lcd_show_string(300, 310, 200, 16, 16, (char *)"Point4 Y:");
	tftlcd_dev.forecolor = LCD_BLUE;
#endif
	/* 设置默认占空比 10% */
	lcd_shownum(50 + 72, 90, 20, 3, 16);
	pwm1_setduty(20);
	printf("entry freertos\r\n");
}

/*
 * @description	: main函数
 * @param 		: 无
 * @return 		: 无
 */
int main(void)
{
	BaseType_t xReturn;

	//硬件初始化
	prvSetupHardware();

	// 进入临界区
	taskENTER_CRITICAL();
	xReturn = xTaskCreate((TaskFunction_t)start_task1, (const char *)"start_task1",
												(uint16_t)256, (void *)NULL, (UBaseType_t)2,
												(TaskHandle_t *)&StartTask1_Handler);
	if (xReturn == pdPASS)
	{
		printf("xTaskCreate1 init\r\n");
	}

	xReturn = xTaskCreate((TaskFunction_t)start_task2, (const char *)"start_task2",
												(uint16_t)4095, (void *)NULL, (UBaseType_t)3,
												(TaskHandle_t *)&StartTask2_Handler);
	if (xReturn == pdPASS)
	{
		printf("xTaskCreate2 init\r\n");
	}
#ifdef CAT_SYSTEM_STATUS
	xReturn = xTaskCreate((TaskFunction_t)cpu_task, (const char *)"cpu_task",
												(uint16_t)512, (void *)NULL, (UBaseType_t)4,
												(TaskHandle_t *)&cputask_Handler);
	if (xReturn == pdPASS)
	{
		printf("cpuTask init\r\n");
	}
#endif
#if configUSE_TIMERS
	VGLSoftwareTimer =
			xTimerCreate((const char *)"VGLExTimer", vglSOFTWARE_TIMER_PERIOD_MS,
									 pdTRUE, (void *)0, VGLTimerCallback);

	xTimerStart(VGLSoftwareTimer, 0);
#endif
	// 退出临界区
	taskEXIT_CRITICAL();

	// 启动任务切换
	if (xReturn == pdPASS)
	{
		vTaskStartScheduler();
	}

	while (1)
	{
		printf("OS should never run to here\r\n");
	}

	return 0;
}

void start_task1(void *pvParameters)
{
	unsigned char keyvalue = 0;
	unsigned char duty = 0;
	unsigned int presstimes = 0;
	printf("start_task1 entry\r\n");
#if 0
	lv_obj_t *label1 = lv_label_create(lv_scr_act(), NULL);
	/*Modify the Label's text*/
	lv_label_set_text(label1, "Hello world for xun");
	/* Align the Label to the center
     * NULL means align on parent (which is the screen now)
     * 0, 0 at the end means an x, y offset after alignment*/
	lv_obj_align(label1, NULL, LV_ALIGN_CENTER, 0, 0);
#endif
	while (1)
	{
		keyvalue = key_getvalue();
		if (keyvalue == KEY0_VALUE)
		{
			duty += 10;			/* 占空比加10% */
			if (duty > 100) /* 如果占空比超过100%，重新从10%开始 */
				duty = 10;
			//lcd_shownum(50 + 72, 90, duty, 3, 16);
			pwm1_setduty(duty); /* 设置占空比 */
			presstimes += 1;
			printf("press key %d times\r\n", presstimes);
		}
		vTaskDelay(20);
	}
}
void start_task2(void *pvParameters)
{
	printf("start_task2 entry\r\n");
	unsigned int timeout = 0;
	while (1)
	{
		vTaskDelay(5);

#ifdef LITTLE_VGL_ENABLE
		lv_task_handler();
#if MY_DEBUG
		// timeout++;
		// printf("counter timout %d\r\n", timeout);
#endif
#else
		if (tftlcd_dev.id == ATK7016 || tftlcd_dev.id == ATK7084)
		{
			lcd_shownum(300 + 72, 110, ft5426_dev.point_num, 1, 16);
			lcd_shownum(300 + 72, 130, ft5426_dev.x[0], 5, 16);
			lcd_shownum(300 + 72, 150, ft5426_dev.y[0], 5, 16);
			lcd_shownum(300 + 72, 170, ft5426_dev.x[1], 5, 16);
			lcd_shownum(300 + 72, 190, ft5426_dev.y[1], 5, 16);
			lcd_shownum(300 + 72, 210, ft5426_dev.x[2], 5, 16);
			lcd_shownum(300 + 72, 230, ft5426_dev.y[2], 5, 16);
			lcd_shownum(300 + 72, 250, ft5426_dev.x[3], 5, 16);
			lcd_shownum(300 + 72, 270, ft5426_dev.y[3], 5, 16);
			lcd_shownum(300 + 72, 290, ft5426_dev.x[4], 5, 16);
			lcd_shownum(300 + 72, 310, ft5426_dev.y[4], 5, 16);
		}
		else if (tftlcd_dev.id == ATK4384 || tftlcd_dev.id == ATK4342)
		{
			lcd_shownum(300 + 72, 110, gt9147_dev.point_num, 1, 16);
			lcd_shownum(300 + 72, 130, gt9147_dev.x[0], 5, 16);
			lcd_shownum(300 + 72, 150, gt9147_dev.y[0], 5, 16);
			lcd_shownum(300 + 72, 170, gt9147_dev.x[1], 5, 16);
			lcd_shownum(300 + 72, 190, gt9147_dev.y[1], 5, 16);
			lcd_shownum(300 + 72, 210, gt9147_dev.x[2], 5, 16);
			lcd_shownum(300 + 72, 230, gt9147_dev.y[2], 5, 16);
			lcd_shownum(300 + 72, 250, gt9147_dev.x[3], 5, 16);
			lcd_shownum(300 + 72, 270, gt9147_dev.y[3], 5, 16);
			lcd_shownum(300 + 72, 290, gt9147_dev.x[4], 5, 16);
			lcd_shownum(300 + 72, 310, gt9147_dev.y[4], 5, 16);
		}
#endif
	}
}
#ifdef CAT_SYSTEM_STATUS
void cpu_task(void *pvParameters)
{
	uint8_t CPU_RunInfo[400];
	while (1)
	{
		memset((char *)&CPU_RunInfo, 0, 400);
		vTaskList((char *)&CPU_RunInfo);
		printf("------------------------------------\r\n");
		printf("task			status			priority			use_stack		  task_num\r\n");
		printf("%s", CPU_RunInfo);
		printf("------------------------------------\r\n");

		memset((char *)&CPU_RunInfo, 0, 400);
		vTaskGetRunTimeStats((char *)&CPU_RunInfo);
		printf("task			run_counter			usage\r\n");
		printf("%s", CPU_RunInfo);
		printf("------------------------------------\r\n");
		vTaskDelay(1000);
	}
}
#endif

#if configUSE_TIMERS
static void VGLTimerCallback(TimerHandle_t xTimer)
{
	/* The timer has expired.  Count the number of times this happens.  The
    timer that calls this function is an auto re-load timer, so it will
    execute periodically. */
//	static int cnt = 0;
//	printf("timers Callback %d\r\n", cnt++);
#ifdef LITTLE_VGL_ENABLE
	lv_tick_inc(5);
	// printf("entry VGLTimerCallback\r\n");
#endif
}

#endif

//#define configCHECK_FOR_STACK_OVERFLOW 1 栈溢出检测
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{
	printf("StackOverflowHook task is %s", pcTaskName);
}
